/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.basics.manager;

import java.util.Collection;
import java.util.List;
import java.util.Set;

import com.genia.toolbox.basics.bean.Delimiter;
import com.genia.toolbox.basics.bean.DisplayObject;
import com.genia.toolbox.basics.bean.Predicate;
import com.genia.toolbox.basics.bean.Transformer;
import com.genia.toolbox.basics.exception.BundledException;
import com.genia.toolbox.basics.exception.technical.TechnicalIOException;

/**
 * Utility methods to deal with collections.
 */
public interface CollectionManager
{

  /**
   * Concat all the elements of a <code>Collection</code> into a
   * <code>String</code>.
   * 
   * @param <TYPE>
   *          the type of the elements of the <code>Collection</code>
   * @param appendable
   *          the <code>Appendable</code>
   * @param array
   *          the elements of the <code>Collection</code>
   * @param delimiter
   *          the <code>Delimiter</code> that prints the separators between
   *          each elements
   * @param dObject
   *          the <code>DisplayObject</code> that prints each element
   * @throws TechnicalIOException
   *           when an I/O problem occurred.
   */
  public <TYPE> void join(Appendable appendable, TYPE[] array, Delimiter delimiter, DisplayObject<TYPE> dObject)
      throws TechnicalIOException;



  /**
   * Concat all the elements of a <code>Collection</code> into a
   * <code>String</code>.
   * 
   * @param <TYPE>
   *          the type of the elements of the <code>Collection</code>
   * @param array
   *          the elements of the <code>Collection</code>
   * @param delimiter
   *          the <code>Delimiter</code> that prints the separators between
   *          each elements
   * @param dObject
   *          the <code>DisplayObject</code> that prints each element
   * @return the concatenation of all the elements of a <code>Collection</code>
   * @throws TechnicalIOException
   *           when an I/O problem occurred.
   */
  public <TYPE> String join(TYPE[] array, Delimiter delimiter, DisplayObject<TYPE> dObject)
      throws TechnicalIOException;



  /**
   * Concat all the elements of a <code>Collection</code> into a
   * <code>String</code>.
   * 
   * @param <TYPE>
   *          the type of the elements of the <code>Collection</code>
   * @param appendable
   *          the <code>Appendable</code>
   * @param iterable
   *          the elements of the <code>Collection</code>
   * @param delimiter
   *          the <code>Delimiter</code> that prints the separators between
   *          each elements
   * @param dObject
   *          the <code>DisplayObject</code> that prints each element
   * @throws TechnicalIOException
   *           when an I/O problem occurred.
   */
  public <TYPE> void join(Appendable appendable, Iterable<? extends TYPE> iterable, Delimiter delimiter, DisplayObject<TYPE> dObject)
      throws TechnicalIOException;



  /**
   * Concat all the elements of a <code>Collection</code> into a
   * <code>String</code>.
   * 
   * @param <TYPE>
   *          the type of the elements of the <code>Collection</code>
   * @param iterable
   *          the elements of the <code>Collection</code>
   * @param delimiter
   *          the <code>Delimiter</code> that prints the separators between
   *          each elements
   * @param dObject
   *          the <code>DisplayObject</code> that prints each element
   * @return the concatenation of all the elements of a <code>Collection</code>
   * @throws TechnicalIOException
   *           when an I/O problem occurred.
   */
  public <TYPE> String join(Iterable<? extends TYPE> iterable, Delimiter delimiter, DisplayObject<TYPE> dObject)
      throws TechnicalIOException;



  /**
   * Return an empty immutable collection if the parameter is null and the
   * parameter itself otherwise.
   * 
   * @param <TYPE>
   *          the type of the elements of the <code>Collection</code>
   * @param collection
   *          the collection that will be checked for null
   * @return <code>collection</code> if it is not null, an empty immutable
   *         collection otherwise
   */
  public <TYPE> Collection<TYPE> notNullCollection(Collection<TYPE> collection);



  /**
   * tranform a collection.
   * 
   * @param <COLLECTION_TYPE>
   *          the type of the collection to return
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param res
   *          the collection to return
   * @param collection
   *          the collection to tranform
   * @param oldPredicate
   *          the {@link Predicate} that old object must verify, or
   *          <code>null</code> if no condition
   * @param newPredicate
   *          the {@link Predicate} that new object must verify, or
   *          <code>null</code> if no condition
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <COLLECTION_TYPE extends Collection<? super NEW_TYPE>, OLD_TYPE, NEW_TYPE> COLLECTION_TYPE transformCollection(final COLLECTION_TYPE res, final Collection<OLD_TYPE> collection,
      Predicate<? super OLD_TYPE> oldPredicate, Predicate<? super NEW_TYPE> newPredicate, Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * tranform a collection.
   * 
   * @param <COLLECTION_TYPE>
   *          the type of the collection to return
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param res
   *          the collection to return
   * @param collection
   *          the collection to tranform
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <COLLECTION_TYPE extends Collection<NEW_TYPE>, OLD_TYPE, NEW_TYPE> COLLECTION_TYPE transformCollection(final COLLECTION_TYPE res, final Collection<OLD_TYPE> collection,
      Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * tranform a collection and return a {@link Set}.
   * 
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param collection
   *          the collection to tranform
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <OLD_TYPE, NEW_TYPE> Set<NEW_TYPE> transformSet(final Collection<OLD_TYPE> collection, Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * tranform a collection and return a {@link List}.
   * 
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param collection
   *          the collection to tranform
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <OLD_TYPE, NEW_TYPE> List<NEW_TYPE> transformList(final Collection<OLD_TYPE> collection, Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * tranform a collection and return a {@link Set}.
   * 
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param collection
   *          the collection to tranform
   * @param oldPredicate
   *          the {@link Predicate} that old object must verify, or
   *          <code>null</code> if no condition
   * @param newPredicate
   *          the {@link Predicate} that new object must verify, or
   *          <code>null</code> if no condition
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <OLD_TYPE, NEW_TYPE> Set<NEW_TYPE> transformSet(final Collection<OLD_TYPE> collection, Predicate<? super OLD_TYPE> oldPredicate, Predicate<NEW_TYPE> newPredicate,
      Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * tranform a collection and return a {@link List}.
   * 
   * @param <OLD_TYPE>
   *          the type of the object of the original collection
   * @param <NEW_TYPE>
   *          the type of the object of the returned collection
   * @param collection
   *          the collection to tranform
   * @param oldPredicate
   *          the {@link Predicate} that old object must verify, or
   *          <code>null</code> if no condition
   * @param newPredicate
   *          the {@link Predicate} that new object must verify, or
   *          <code>null</code> if no condition
   * @param transformer
   *          the {@link Transformer} that will transforms object from the old
   *          collection to the new collection
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <OLD_TYPE, NEW_TYPE> List<NEW_TYPE> transformList(final Collection<OLD_TYPE> collection, Predicate<? super OLD_TYPE> oldPredicate, Predicate<NEW_TYPE> newPredicate,
      Transformer<OLD_TYPE, NEW_TYPE> transformer)
      throws BundledException;



  /**
   * filter a collection.
   * 
   * @param <COLLECTION_TYPE>
   *          the type of the collection to return
   * @param <TYPE>
   *          the type of the object of the collection
   * @param res
   *          the collection to return
   * @param collection
   *          the collection to tranform
   * @param predicate
   *          the {@link Predicate} that objects must verify, or
   *          <code>null</code> if no condition
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <COLLECTION_TYPE extends Collection<? super TYPE>, TYPE> COLLECTION_TYPE filterCollection(final COLLECTION_TYPE res, final Collection<TYPE> collection, Predicate<? super TYPE> predicate)
      throws BundledException;



  /**
   * filter a collection and return a {@link List}.
   * 
   * @param <TYPE>
   *          the type of the object of the collection
   * @param collection
   *          the collection to tranform
   * @param predicate
   *          the {@link Predicate} that objects must verify, or
   *          <code>null</code> if no condition
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <TYPE> List<TYPE> filterList(final Collection<TYPE> collection, Predicate<? super TYPE> predicate)
      throws BundledException;



  /**
   * filter a collection and return a {@link Set}.
   * 
   * @param <TYPE>
   *          the type of the object of the collection
   * @param collection
   *          the collection to tranform
   * @param predicate
   *          the {@link Predicate} that objects must verify, or
   *          <code>null</code> if no condition
   * @return the transformed collection
   * @throws BundledException
   *           when an error occurred
   */
  public <TYPE> Set<TYPE> filterSet(final Collection<TYPE> collection, Predicate<? super TYPE> predicate)
      throws BundledException;



  /**
   * fill the first collection with all the elements of the other collections
   * and returns the first collection.
   * 
   * @param <TYPE>
   *          the type of the elements of the collections
   * @param <COLLECTION>
   *          the type of the returned collection
   * @param collection
   *          the collection to fill and that will be returned
   * @param iterables
   *          the collections to aggregate
   * @return the first collection with all the elements of the other collections
   */
  public <TYPE, COLLECTION extends Collection<TYPE>> COLLECTION aggregate(final COLLECTION collection, final Iterable<? extends TYPE>... iterables);
}
